﻿/*
* Copyright (c) 2010-2012 Tesla Engine Group
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* 
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/


using System;
using Tesla.Direct3D10.Graphics.Implementation;
using Tesla.Graphics;
using Tesla.Math;
using D3D = SlimDX.Direct3D10;
using D3DC = SlimDX.D3DCompiler;
using SDX = SlimDX;

namespace Tesla.Direct3D10.Graphics {
    /// <summary>
    /// Concrete Direct3D10 implementation of <see cref="IEffectParameter"/>.
    /// </summary>
    public sealed class D3D10EffectParameter : IEffectParameter {

        private D3D.EffectVariable _param;
        private String _name;
        private String _semantic;
        private D3D10EffectParameterCollection _elements;
        private D3D10EffectParameterCollection _structMembers;
        private D3D10EffectAnnotationCollection _annotations;
        private EffectParameterClass _paramClass;
        private EffectParameterType _paramType;
        private int _columnCount;
        private int _rowCount;

        //When converting param class, keep track if its column or row major so we can do the proper transposing when setting data.
        private bool _isColumnMatrix;

        //Buffers for translating & passing array values (INFO: Maybe pool these?)
        private D3D.ShaderResourceView[] _srvArray;
        private SDX.DataStream _elementArray;

        //Weak references to textures for use in GetValueTexture*() methods
        private WeakReference _cachedTexture;
        private WeakReference[] _cachedTextureArray;

        /// <summary>
        /// Gets the name of the parameter.
        /// </summary>
        public String Name {
            get {
                return _name;
            }
        }

        /// <summary>
        /// Gets the semantic of the parameter, if it exists.
        /// </summary>
        public String Semantic {
            get {
                return _semantic;
            }
        }

        /// <summary>
        /// Gets the array elements of the parameter, if it is an array.
        /// </summary>
        public IEffectParameterCollection Elements {
            get {
                return _elements;
            }
        }

        /// <summary>
        /// Gets the structure members of the parameter, if it is a struct.
        /// </summary>
        public IEffectParameterCollection StructureMembers {
            get {
                return _structMembers;
            }
        }

        /// <summary>
        /// Gets the collection of annotations that decorate the parameter.
        /// </summary>
        public IEffectAnnotationCollection Annotations {
            get {
                return _annotations;
            }
        }

        /// <summary>
        /// Gets the enumeration that specifies the parameter's classification.
        /// </summary>
        public EffectParameterClass ParameterClass {
            get {
                return _paramClass;
            }
        }

        /// <summary>
        /// Gets the enumeration that specifies the parameter's type.
        /// </summary>
        public EffectParameterType ParameterType {
            get {
                return _paramType;
            }
        }

        /// <summary>
        /// Gets the number of columns in the class of this parameter.
        /// </summary>
        public int ColumnCount {
            get {
                return _columnCount;
            }
        }

        /// <summary>
        /// Gets the number of rows in the class of this parameter.
        /// </summary>
        public int RowCount {
            get {
                return _rowCount;
            }
        }

        /// <summary>
        /// Gets the actual D3D10 effect variable object.
        /// </summary>
        internal D3D.EffectVariable D3D10EffectVariable {
            get {
                return _param;
            }
        }

        /// <summary>
        /// Creates a new instance of <see cref="D3D10EffectParameter"/>, for when the parameter is cloned.
        /// </summary>
        /// <param name="param">The D3D10 effect parameter</param>
        /// <param name="oldParameter">Old parameter we're cloning.</param>
        internal D3D10EffectParameter(D3D.EffectVariable param, D3D10EffectParameter oldParameter) {
            D3D.EffectVariableDescription desc = param.Description;
            _name = desc.Name;
            _semantic = desc.Semantic;
            _param = param;
            _paramClass = oldParameter._paramClass;
            _paramType = oldParameter._paramType;
            _rowCount = oldParameter._rowCount;
            _columnCount = oldParameter._columnCount;
            _isColumnMatrix = oldParameter._isColumnMatrix;

            ExplicitlyCast();

            //Fetch annotations
            int annoCount = desc.AnnotationCount;
            FetchAnnotations(annoCount);

            //Fill in elements/members later
            _elements = new D3D10EffectParameterCollection();
            _structMembers = new D3D10EffectParameterCollection();
        }

        /// <summary>
        /// Creates a new instance of <see cref="D3D10EffectParameter"/> where the parameter is inside an array
        /// or struct.
        /// </summary>
        /// <param name="param">The D3D10 effect parameter</param>
        /// <param name="reflectType">Reflection type.</param>

        internal D3D10EffectParameter(D3D.EffectVariable param, D3DC.ShaderReflectionType reflectType) {
            D3D.EffectVariableDescription desc = param.Description;
            _name = desc.Name;
            _semantic = desc.Semantic;
            _param = param;

            //Fetch annotations
            int annoCount = desc.AnnotationCount;
            FetchAnnotations(annoCount);

            //Set the rest of the fields
            D3DC.ShaderTypeDescription typeDesc = reflectType.Description;
            SetClassAndType(typeDesc.Class, typeDesc.Type);
            ExplicitlyCast();
            _rowCount = typeDesc.Rows;
            _columnCount = typeDesc.Columns;

            //Check for elements
            int elementCount = typeDesc.Elements;
            _elements = new D3D10EffectParameterCollection();
            for(int i = 0; i < elementCount; i++) {
                D3D.EffectVariable elem = _param.GetElement(i);
                if(elem.IsValid) {
                    _elements.Add(new D3D10EffectParameter(_param.GetElement(i), reflectType, true));
                }
            }

            CreateElementArray();


            //Check for struct members
            int memberCount = typeDesc.Members;
            _structMembers = new D3D10EffectParameterCollection();
            if(_paramClass == EffectParameterClass.Struct && elementCount == 0) {
                for(int i = 0; i < memberCount; i++) {
                    D3D.EffectVariable member = _param.GetMemberByIndex(i);
                    if(member.IsValid) {
                        _structMembers.Add(new D3D10EffectParameter(member, reflectType.GetMemberType(i)));
                    }
                }
            }
        }

        /// <summary>
        /// Creates a new instance of <see cref="D3D10EffectParameter"/> that is a non-texture parameter that may be an element of another.
        /// </summary>
        /// <param name="param">The D3D10 efrfect parameter</param>
        /// <param name="reflectType">Reflection type</param>
        /// <param name="isElement">True if an element in an array, false otherwise.</param>
        internal D3D10EffectParameter(D3D.EffectVariable param, D3DC.ShaderReflectionType reflectType, bool isElement) {
            D3D.EffectVariableDescription desc = param.Description;
            _name = desc.Name;
            _semantic = desc.Semantic;
            _param = param;

            //Fetch annotations
            int annoCount = desc.AnnotationCount;
            FetchAnnotations(annoCount);

            //Set the rest of the fields
            D3DC.ShaderTypeDescription typeDesc = reflectType.Description;
            SetClassAndType(typeDesc.Class, typeDesc.Type);
            ExplicitlyCast();
            _rowCount = typeDesc.Rows;
            _columnCount = typeDesc.Columns;

            //Check for elements
            int elementCount = typeDesc.Elements;
            _elements = new D3D10EffectParameterCollection();
            //If not an element, parameter represents an array, so parse the elements it should contain
            if(!isElement) {
                for(int i = 0; i < elementCount; i++) {
                    D3D.EffectVariable elem = _param.GetElement(i);
                    if(elem.IsValid) {
                        _elements.Add(new D3D10EffectParameter(_param.GetElement(i), reflectType));
                    }
                }
                CreateElementArray();
            }

            //Check for struct members
            int memberCount = typeDesc.Members;
            _structMembers = new D3D10EffectParameterCollection();
            //Do not process struct members if the parameter represents an array
            if(_paramClass == EffectParameterClass.Struct && (isElement || elementCount == 0)) {
                for(int i = 0; i < memberCount; i++) {
                    D3D.EffectVariable member = _param.GetMemberByIndex(i);
                    if(member.IsValid) {
                        _structMembers.Add(new D3D10EffectParameter(member, reflectType.GetMemberType(i)));
                    }
                }
            }
        }

        /// <summary>
        /// Creates a new instance of <see cref="D3D10EffectParameter"/>, that is a texture parameter.
        /// </summary>
        /// <param name="param">The D3D10 effect variable</param>
        /// <param name="inputBinding">The reflection input binding description</param>
        internal D3D10EffectParameter(D3D.EffectVariable param, D3DC.InputBindingDescription inputBinding) {
            D3D.EffectVariableDescription desc = param.Description;
            _name = desc.Name;
            _semantic = desc.Semantic;
            _rowCount = 0;
            _columnCount = 0;
            _param = param.AsResource();
            _paramClass = EffectParameterClass.Object;
 
            switch(inputBinding.Dimension) {
                case SDX.Direct3D11.ShaderResourceViewDimension.Texture1D:
                case SDX.Direct3D11.ShaderResourceViewDimension.Texture1DArray:
                    _paramType = EffectParameterType.Texture1D;
                    break;
                case SDX.Direct3D11.ShaderResourceViewDimension.Texture2D:
                case SDX.Direct3D11.ShaderResourceViewDimension.Texture2DArray:
                    _paramType = EffectParameterType.Texture2D;
                    break;
                case SDX.Direct3D11.ShaderResourceViewDimension.Texture3D:
                    _paramType = EffectParameterType.Texture3D;
                    break;
                case SDX.Direct3D11.ShaderResourceViewDimension.TextureCube:
                case SDX.Direct3D11.ShaderResourceViewDimension.TextureCubeArray:
                    _paramType = EffectParameterType.TextureCube;
                    break;
                default:
                    _paramType = EffectParameterType.Unknown;
                    break;
            }

            //Fetch annotations
            int annoCount = desc.AnnotationCount;
            FetchAnnotations(annoCount);

            //Check for elements
            _elements = new D3D10EffectParameterCollection();
            D3D.EffectVariable elem;
            int k = 0;
            while((elem = _param.GetElement(k)) != null) {
                if(elem.IsValid) {
                    _elements.Add(new D3D10EffectParameter(elem, inputBinding));
                } else {
                    break;
                }
                k++;
            }

            CreateTextureArray();

            //No struct data
            _structMembers = new D3D10EffectParameterCollection();
        }

        //Get the annotations best we can
        private void FetchAnnotations(int annoCount) {
            _annotations = new D3D10EffectAnnotationCollection();
            for(int i = 0; i < annoCount; i++) {
                D3D.EffectVariable anno = _param.GetAnnotationByIndex(i);
                D3D.EffectVariableDescription annoDesc = anno.Description;
                D3D.EffectVariable annoVar = anno.AsString();
                if(annoVar != null) {
                    _annotations.Add(new D3D10EffectAnnotation(annoVar, annoDesc.Name, annoDesc.Semantic, EffectParameterClass.Object, EffectParameterType.String));
                    continue;
                }
                annoVar = anno.AsScalar();
                if(annoVar != null) {
                    _annotations.Add(new D3D10EffectAnnotation(annoVar, annoDesc.Name, annoDesc.Semantic, EffectParameterClass.Scalar, EffectParameterType.Unknown));
                    continue;
                }
                annoVar = anno.AsMatrix();
                if(annoVar != null) {
                    _annotations.Add(new D3D10EffectAnnotation(annoVar, annoDesc.Name, annoDesc.Semantic, EffectParameterClass.Matrix, EffectParameterType.Unknown));
                    continue;
                }
                annoVar = anno.AsVector();
                if(annoVar != null) {
                    _annotations.Add(new D3D10EffectAnnotation(annoVar, annoDesc.Name, annoDesc.Semantic, EffectParameterClass.Vector, EffectParameterType.Unknown));
                }
            }
        }

        //Figure out the class and type from the reflection info
        private void SetClassAndType(D3DC.ShaderVariableClass varClass, D3DC.ShaderVariableType varType) {
            switch(varClass) {
                case D3DC.ShaderVariableClass.Scalar:
                    _paramClass = EffectParameterClass.Scalar;
                    break;
                case D3DC.ShaderVariableClass.Vector:
                    _paramClass = EffectParameterClass.Vector;
                    break;
                case D3DC.ShaderVariableClass.MatrixColumns:
                    _isColumnMatrix = true;
                    _paramClass = EffectParameterClass.Matrix;
                    break;
                case D3DC.ShaderVariableClass.MatrixRows:
                    _isColumnMatrix = false;
                    _paramClass = EffectParameterClass.Matrix;
                    break;
                case D3DC.ShaderVariableClass.Object:
                    _paramClass = EffectParameterClass.Object;
                    break;
                case D3DC.ShaderVariableClass.Struct:
                    _paramClass = EffectParameterClass.Struct;
                    break;
            }
            switch(varType) {
                case D3DC.ShaderVariableType.Bool:
                    _paramType = EffectParameterType.Bool;
                    break;
                case D3DC.ShaderVariableType.Float:
                    _paramType = EffectParameterType.Single;
                    break;
                case D3DC.ShaderVariableType.Int:
                    _paramType = EffectParameterType.Int32;
                    break;
                case D3DC.ShaderVariableType.String:
                    _paramType = EffectParameterType.String;
                    break;
                case D3DC.ShaderVariableType.Texture:
                    _paramType = EffectParameterType.Texture;
                    break;
                case D3DC.ShaderVariableType.Texture1D:
                case D3DC.ShaderVariableType.Texture1DArray:
                    _paramType = EffectParameterType.Texture1D;
                    break;
                case D3DC.ShaderVariableType.Texture2D:
                case D3DC.ShaderVariableType.Texture2DArray:
                    _paramType = EffectParameterType.Texture2D;
                    break;
                case D3DC.ShaderVariableType.Texture3D:
                    _paramType = EffectParameterType.Texture3D;
                    break;
                case D3DC.ShaderVariableType.TextureCube:
                case D3DC.ShaderVariableType.TextureCubeArray:
                    _paramType = EffectParameterType.TextureCube;
                    break;
                case D3DC.ShaderVariableType.Void:
                    _paramType = EffectParameterType.Void;
                    break;
                default:
                    _paramType = EffectParameterType.Unknown;
                    break;
            }
        }

        //Set the variable contained as an explicit subclass.
        private void ExplicitlyCast() {
            switch(_paramClass) {
                case EffectParameterClass.Scalar:
                    _param = _param.AsScalar();
                    return;
                case EffectParameterClass.Matrix:
                    _param = _param.AsMatrix();
                    return;
                case EffectParameterClass.Vector:
                    _param = _param.AsVector();
                    return;
                case EffectParameterClass.Object:
                    switch(_paramType) {
                        case EffectParameterType.String:
                            _param = _param.AsString();
                            break;
                        case EffectParameterType.Texture:
                        case EffectParameterType.Texture1D:
                        case EffectParameterType.Texture2D:
                        case EffectParameterType.Texture3D:
                        case EffectParameterType.TextureCube:
                            _param = _param.AsResource();
                            break;
                    }
                    return;
            }
        }

        //Check if the variable is an array
        private bool IsArray() {
            if(_elements.Count > 0) {
                return true;
            } else {
                return false;
            }
        }

        //Check if the variable is a Vector2, Vector3, or Vector4
        private bool IsVector(int count) {
            if(count < 2 || count > 4) {
                return false;
            }

            return _rowCount == 1 && _columnCount == count;
        }

        //Create a buffer used to save textures passed, also creates the shader resource view array used for passing values
        //to SlimDX
        private void CreateTextureArray() {
            if(IsArray()) {
                switch(_paramClass) {
                    case EffectParameterClass.Object:
                        switch(_paramType) {
                            case EffectParameterType.Texture:
                            case EffectParameterType.Texture1D:
                            case EffectParameterType.Texture2D:
                            case EffectParameterType.Texture3D:
                            case EffectParameterType.TextureCube:
                                _cachedTextureArray = new WeakReference[_elements.Count];
                                _srvArray = new D3D.ShaderResourceView[_elements.Count];
                                break;
                        }
                        break;
                }
            }
        }

        //Create a buffer used to translate & pass array vector/matrix values
        private void CreateElementArray() {
            if(IsArray()) {
                switch(_paramClass) {
                    case EffectParameterClass.Vector:
                        switch(_columnCount) {
                            case 2:
                                _elementArray = new SDX.DataStream(_elements.Count * Vector2.SizeInBytes, true, true);
                                break;
                            case 3:
                                _elementArray = new SDX.DataStream(_elements.Count * Vector3.SizeInBytes, true, true);
                                break;
                            case 4:
                                _elementArray = new SDX.DataStream(_elements.Count * Vector4.SizeInBytes, true, true);
                                break;
                        }
                        break;
                    case EffectParameterClass.Matrix:
                        _elementArray = new SDX.DataStream(_elements.Count * Matrix.SizeInBytes, true, true);
                        break;
                }
            }
        }

        /// <summary>
        /// Creates a clone using the specified D3D10 effect variable and this parameter's fields.
        /// The effect variable should be the same type of variable, but extracted from another instance
        /// of the effect.
        /// </summary>
        /// <param name="param">The effect variable to use.</param>
        /// <returns>Cloned parameter</returns>
        internal D3D10EffectParameter Clone(D3D.EffectVariable param) {
            D3D.EffectVariableDescription desc = param.Description;
            D3D10EffectParameter clone = new D3D10EffectParameter(param, this);

            //Clone elements and members
            D3D.EffectVariable elem;
            int k = 0;
            if(_elements.Count != 0) {
                while((elem = param.GetElement(k)) != null) {
                    if(elem.IsValid) {
                        D3D10EffectParameter elemToClone = (D3D10EffectParameter) _elements[k];
                        if(elemToClone != null) {
                            ((D3D10EffectParameterCollection) clone.Elements).Add(elemToClone.Clone(elem));
                        }
                    } else {
                        break;
                    }
                    k++;
                }
                CreateElementArray();
                CreateTextureArray();
            } else if(_paramClass == EffectParameterClass.Struct) {
                while((elem = param.GetMemberByIndex(k)) != null) {
                    if(elem.IsValid) {
                        D3D10EffectParameter elemToClone = (D3D10EffectParameter) _structMembers[k];
                        if(elemToClone != null) {
                            ((D3D10EffectParameterCollection) clone.StructureMembers).Add(elemToClone.Clone(elem));
                        }
                    } else {
                        break;
                    }
                    k++;
                }
            }
            return clone;
        }

        /// <summary>
        /// Gets the value of the parameter as a bool.
        /// </summary>
        /// <returns>Bool value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a bool.</exception>
        public  bool GetValueBoolean() {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Bool
                || IsArray()) {
                throw new InvalidCastException("Parameter is not a boolean.");
            }

            return ((D3D.EffectScalarVariable) _param).GetBool();
        }
        /// <summary>
        /// Gets the value of the parameter as an array of bools.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>he bool array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a bool array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public bool[] GetValueBooleanArray(int count) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Bool
                || !IsArray()) {
                throw new InvalidCastException("Parameter is not a bool[]");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            return ((D3D.EffectScalarVariable) _param).GetBoolArray(count);
        }

        /// <summary>
        /// Gets the value of the parameter as a single.
        /// </summary>
        /// <returns>The single value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a single.</exception>
        public float GetValueSingle() {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Single
                || IsArray()) {
                throw new InvalidCastException("Parameter is not a float.");
            }

            return ((D3D.EffectScalarVariable) _param).GetFloat();
        }
        /// <summary>
        /// Gets the value of the parameter as an array of singles.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The single array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a single array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public float[] GetValueSingleArray(int count) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Single
                || !IsArray()) {
                throw new InvalidCastException("Parameter is not a float[].");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            return ((D3D.EffectScalarVariable) _param).GetFloatArray(count);
        }

        /// <summary>
        /// Gets the value of the parameter as an int.
        /// </summary>
        /// <returns>The int value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not an int.</exception>
        public int GetValueInt() {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Int32
                || IsArray()) {
                throw new InvalidCastException("Parameter is not an int.");
            }

            return ((D3D.EffectScalarVariable) _param).GetInt();
        }

        /// <summary>
        /// Gets the value of the parameter as an array of ints.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The int array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not an int array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public int[] GetValueIntArray(int count) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Int32
                || !IsArray()) {
                throw new InvalidCastException("Parameter is not int[]");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            return ((D3D.EffectScalarVariable) _param).GetIntArray(count);
        }


        /// <summary>
        /// Gets the value of the parameter as a matrix.
        /// </summary>
        /// <returns>The matrix value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a matrix.</exception>
        public Matrix GetValueMatrix() {
            if(_paramClass != EffectParameterClass.Matrix || IsArray()) {
                throw new InvalidCastException("Parameter is not a Matrix.");
            }

            SDX.DataStream ds = _param.GetRawValue(sizeof(float) * _columnCount * _rowCount);
            ds.Position = 0;

            Matrix m = new Matrix();
            //If column-major (default), must transpose
            if(_isColumnMatrix) {
                for(int i = 1; i <= _rowCount; i++) {
                    for(int j = 1; j <= _columnCount; j++) {
                        m[j, i] = ds.Read<float>();
                    }
                }
            } else {
                for(int i = 1; i <= _rowCount; i++) {
                    for(int j = 1; j <= _columnCount; j++) {
                        m[i, j] = ds.Read<float>();
                    }
                }
            }

            ds.Dispose();

            return m;
        }

        /// <summary>
        /// Gets the value of the parameter as an array of matrices.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The matrix array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a matrix array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public Matrix[] GetValueMatrixArray(int count) {
            if(_paramClass != EffectParameterClass.Matrix || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Matrix[].");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Matrix[] array = new Matrix[count];
            SDX.DataStream ds = _param.GetRawValue(sizeof(float) * _columnCount * _rowCount * count);
            ds.Position = 0;

            for(int k = 0; k < count; k++) {
                Matrix m = new Matrix();
                //If column-major (default), must transpose raw data
                if(_isColumnMatrix) {
                    for(int i = 1; i <= _rowCount; i++) {
                        for(int j = 1; j <= _columnCount; j++) {
                            m[j, i] = ds.Read<float>();
                        }
                    }
                } else {
                    for(int i = 1; i <= _rowCount; i++) {
                        for(int j = 1; j <= _columnCount; j++) {
                            m[i, j] = ds.Read<float>();
                        }
                    }
                }
                array[k] = m;
            }

            ds.Dispose();

            return array;
        }

        /// <summary>
        /// Gets the value of the parameter as a matrix transpose.
        /// </summary>
        /// <returns>The matrix transpose value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a matrix transpose.</exception>
        public Matrix GetValueMatrixTranspose() {
            if(_paramClass != EffectParameterClass.Matrix || IsArray()) {
                throw new InvalidCastException("Parameter is not a Matrix.");
            }

            SDX.DataStream ds = _param.GetRawValue(sizeof(float) * _columnCount * _rowCount);
            ds.Position = 0;

            Matrix m = new Matrix();
            //If column-major (default), reading raw bytes will already be in transposed format
            if(_isColumnMatrix) {
                for(int i = 1; i <= _rowCount; i++) {
                    for(int j = 1; j <= _columnCount; j++) {
                        m[i, j] = ds.Read<float>();
                    }
                }
            } else {
                //Transpose for row-major
                for(int i = 1; i <= _rowCount; i++) {
                    for(int j = 1; j <= _columnCount; j++) {
                        m[j, i] = ds.Read<float>();
                    }
                }
            }

            ds.Dispose();

            return m;
        }

        /// <summary>
        /// Gets the value of the parameter as an array of matrix transposes.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The matrix transpose array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a matrix transpose array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public Matrix[] GetValueMatrixTransposeArray(int count) {
            if(_paramClass != EffectParameterClass.Matrix || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Matrix[].");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Matrix[] array = new Matrix[count];
            SDX.DataStream ds = _param.GetRawValue(sizeof(float) * _columnCount * _rowCount * count);
            ds.Position = 0;

            for(int k = 0; k < count; k++) {
                Matrix m = new Matrix();
                //If column-major (default), writing raw bytes will already be in transposed format
                if(_isColumnMatrix) {
                    for(int i = 1; i <= _rowCount; i++) {
                        for(int j = 1; j <= _columnCount; j++) {
                            m[i, j] = ds.Read<float>();
                        }
                    }
                } else {
                    //Transpose for row-major
                    for(int i = 1; i <= _rowCount; i++) {
                        for(int j = 1; j <= _columnCount; j++) {
                            m[j, i] = ds.Read<float>();
                        }
                    }
                }
                array[k] = m;
            }

            ds.Dispose();

            return array;
        }

        /// <summary>
        /// Gets the value of the parameter as a quaternion.
        /// </summary>
        /// <returns>The quaternion value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a quaternion.</exception>
        public Quaternion GetValueQuaternion() {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(4) || IsArray()) {
                throw new InvalidCastException("Parameter is not a 4 component vector.");
            }

            SDX.DataStream ds = _param.GetRawValue(Quaternion.SizeInBytes);
            ds.Position = 0;

            Quaternion q;
            q.X = ds.Read<float>();
            q.Y = ds.Read<float>();
            q.Z = ds.Read<float>();
            q.W = ds.Read<float>();

            ds.Dispose();

            return q;
        }

        /// <summary>
        /// Gets the value of the parameter as an array of quaternions.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The quaternion array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a quaternion array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public Quaternion[] GetValueQuaternionArray(int count) {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(4) ||!IsArray()) {
                throw new InvalidCastException("Parameter is not a 4 component vector array.");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Quaternion[] array = new Quaternion[count];
            SDX.DataStream ds = _param.GetRawValue(Quaternion.SizeInBytes * count);
            ds.Position = 0;

            for(int i = 0; i < count; i++) {
                array[i] = new Quaternion(ds.Read<float>(), ds.Read<float>(), ds.Read<float>(), ds.Read<float>());
            }

            ds.Dispose();

            return array;
        }

        /// <summary>
        /// Gets the value of the parameter as a RGBA color.
        /// </summary>
        /// <returns>The RGBA color value</returns>
        public Color GetValueColor() {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(4) || IsArray()) {
                throw new InvalidCastException("Parameter is not a 4 component vector.");
            }

            SDX.DataStream ds = _param.GetRawValue(Vector4.SizeInBytes);
            ds.Position = 0;

            float r = ds.Read<float>();
            float g = ds.Read<float>();
            float b = ds.Read<float>();
            float a = ds.Read<float>();

            ds.Dispose();

            return new Color(r, g, b, a);
        }

        /// <summary>
        /// Gets the value of the parameter as an array of RGBA colors.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The quaternion array</returns>
        public Color[] GetValueColorArray(int count) {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(4) ||!IsArray()) {
                throw new InvalidCastException("Parameter is not a 4 component vector array.");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Color[] array = new Color[count];
            SDX.DataStream ds = _param.GetRawValue(Vector4.SizeInBytes * count);
            ds.Position = 0;

            for(int i = 0; i < count; i++) {
                array[i] = new Color(ds.Read<float>(), ds.Read<float>(), ds.Read<float>(), ds.Read<float>());
            }

            ds.Dispose();

            return array;
        }

        /// <summary>
        /// Gets the value of the parameter as a vector2.
        /// </summary>
        /// <returns>The vector2 value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a vector2.</exception>
        public Vector2 GetValueVector2() {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(2) || IsArray()) {
                throw new InvalidCastException("Parameter is not a Vector2.");
            }

            SDX.DataStream ds = _param.GetRawValue(Vector2.SizeInBytes);
            ds.Position = 0;

            Vector2 v;
            //INFO: Implict int -> float yields garbage values here, but in the GetValueVector*Array methods it works fine...
            switch(_paramType) {
                case EffectParameterType.Int32:
                    v.X = ds.Read<int>();
                    v.Y = ds.Read<int>();
                    break;
                default:
                    v.X = ds.Read<float>();
                    v.Y = ds.Read<float>();
                    break;
            }

            ds.Dispose();

            return v;
        }


        /// <summary>
        /// Gets the value of the parameter as an array of vector2's.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The vector2 array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a vector2 array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public Vector2[] GetValueVector2Array(int count) {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(2) || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Vector2[].");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Vector2[] array = new Vector2[count];
            SDX.DataStream ds = _param.GetRawValue(Vector2.SizeInBytes * count);
            ds.Position = 0;

            for(int i = 0; i < count; i++) {
                array[i] = new Vector2(ds.Read<float>(), ds.Read<float>());
            }

            ds.Dispose();

            return array;
        }


        /// <summary>
        /// Gets the value of the parameter as a vector3.
        /// </summary>
        /// <returns>The vector3 value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a vector3.</exception>
        public Vector3 GetValueVector3() {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(3) || IsArray()) {
                throw new InvalidCastException("Parameter is not a Vector3.");
            }

            SDX.DataStream ds = _param.GetRawValue(Vector3.SizeInBytes);
            ds.Position = 0;

            Vector3 v;
            //INFO: Implict int -> float yields garbage values here, but in the GetValueVector*Array methods it works fine...
            switch(_paramType) {
                case EffectParameterType.Int32:
                    v.X = ds.Read<int>();
                    v.Y = ds.Read<int>();
                    v.Z = ds.Read<int>();
                    break;
                default:
                    v.X = ds.Read<float>();
                    v.Y = ds.Read<float>();
                    v.Z = ds.Read<float>();
                    break;
            }

            ds.Dispose();

            return v;
        }

        /// <summary>
        /// Gets the value of the parameter as an array of vector3's.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The vector3 array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a vector3 array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public Vector3[] GetValueVector3Array(int count) {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(3) || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Vector3[].");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Vector3[] array = new Vector3[count];
            SDX.DataStream ds = _param.GetRawValue(Vector3.SizeInBytes * count);
            ds.Position = 0;

            for(int i = 0; i < count; i++) {
                array[i] = new Vector3(ds.Read<float>(), ds.Read<float>(), ds.Read<float>());
            }

            ds.Dispose();

            return array;
        }

        /// <summary>
        /// Gets the value of the parameter as a vector4.
        /// </summary>
        /// <returns>The vector4 value </returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a vector4.</exception>
        public Vector4 GetValueVector4() {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(4) || IsArray()) {
                throw new InvalidCastException("Parameter is not a Vector4.");
            }

            SDX.DataStream ds = _param.GetRawValue(Vector4.SizeInBytes);
            ds.Position = 0;

            Vector4 v;
            //INFO: Implict int -> float yields garbage values here, but in the GetValueVector*Array methods it works fine...
            switch(_paramType) {
                case EffectParameterType.Int32:
                    v.X = ds.Read<int>();
                    v.Y = ds.Read<int>();
                    v.Z = ds.Read<int>();
                    v.W = ds.Read<int>();
                    break;
                default:
                    v.X = ds.Read<float>();
                    v.Y = ds.Read<float>();
                    v.Z = ds.Read<float>();
                    v.W = ds.Read<float>();
                    break;
            }

            ds.Dispose();

            return v;
        }

        /// <summary>
        /// Gets the value of the parameter as an array of vector4's.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>The vector4 array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a vector4 array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public Vector4[] GetValueVector4Array(int count) {
            if(_paramClass != EffectParameterClass.Vector || !IsVector(4) || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Vector4[].");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Vector4[] array = new Vector4[count];
            SDX.DataStream ds = _param.GetRawValue(Vector4.SizeInBytes * count);
            ds.Position = 0;

            for(int i = 0; i < count; i++) {
                array[i] = new Vector4(ds.Read<float>(), ds.Read<float>(), ds.Read<float>(), ds.Read<float>());
            }

            ds.Dispose();

            return array;
        }

        /// <summary>
        /// Gets the value of the parameter as a String.
        /// </summary>
        /// <returns>The string value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a string.</exception>
        public String GetValueString() {
            if(_paramClass != EffectParameterClass.Object || _paramType != EffectParameterType.String) {
                throw new InvalidCastException("Parameter is not a string.");
            }

            return ((D3D.EffectStringVariable) _param).GetString();
        }

        /// <summary>
        /// Gets the value of the parameter as a Texture1D.
        /// </summary>
        /// <returns>The texture value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Texture1D.</exception>
        public Texture1D GetValueTexture1D() {
            if(_paramClass != EffectParameterClass.Object || _paramType != EffectParameterType.Texture1D) {
                throw new InvalidCastException("Parameter is not a Texture1D");
            }

            if(_cachedTexture != null) {
                //Still may be null if the texture was released
                return _cachedTexture.Target as Texture1D;
            } else {
                return null;
            }
        }

        /// <summary>
        /// Gets the value of the parameter as a Texture2D.
        /// </summary>
        /// <returns>The texture value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Texture2D.</exception>
        public Texture2D GetValueTexture2D() {
            if(_paramClass != EffectParameterClass.Object || _paramType != EffectParameterType.Texture2D) {
                throw new InvalidCastException("Parameter is not a Texture2D");
            }

            if(_cachedTexture != null) {
                //Still may be null, if the texture was released
                return _cachedTexture.Target as Texture2D;
            } else {
                return null;
            }
        }

        /// <summary>
        /// Gets the value of the parameter as a Texture3D.
        /// </summary>
        /// <returns>The texture value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Texture3D.</exception>
        public Texture3D GetValueTexture3D() {
            if(_paramClass != EffectParameterClass.Object || _paramType != EffectParameterType.Texture3D) {
                throw new InvalidCastException("Parameter is not a Texture3D");
            }

            if(_cachedTexture != null) {
                //Still may be null, if the texture was released
                return _cachedTexture.Target as Texture3D;
            } else {
                return null;
            }
        }

        /// <summary>
        /// Gets the value of the parameter as a TextureCube.
        /// </summary>
        /// <returns>The texture value</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a TextureCube.</exception>
        public TextureCube GetValueTextureCube() {
            if(_paramClass != EffectParameterClass.Object || _paramType != EffectParameterType.TextureCube) {
                throw new InvalidCastException("Parameter is not a TextureCube");
            }

            if(_cachedTexture != null) {
                //Still may be null, if the texture was released
                return _cachedTexture.Target as TextureCube;
            } else {
                return null;
            }
        }

        /// <summary>
        /// Gets the value of the parameter as an array of textures.
        /// </summary>
        /// <param name="count">Number of elements to get</param>
        /// <returns>Texture array</returns>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a texture array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the element count is out of range.</exception>
        public Texture[] GetValueTextureArray(int count) {
            if(_paramClass != EffectParameterClass.Object || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Texture array.");
            }

            if(count <= 0 || count > _elements.Count) {
                throw new ArgumentOutOfRangeException("count", "Element count is out of range.");
            }

            Texture[] array = new Texture[count];

            for(int i = 0; i < count; i++) {
                WeakReference wref = _cachedTextureArray[i];
                if(wref != null) {
                    //May be null, if the texture was released
                    array[i] = wref.Target as Texture;
                } else {
                    array[i] = null;
                }
            }

            return array;
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Bool value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a bool.</exception>
        public void SetValue(bool value) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Bool
                || IsArray()) {
                throw new InvalidCastException("Parameter is not a boolean.");
            }

            SlimDX.Result r = ((D3D.EffectScalarVariable) _param).Set(value);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }


        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of bools</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a bool array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(bool[] values) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Bool
                || !IsArray()) {
                throw new InvalidCastException("Parameter is not a bool[]");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                SlimDX.Result r = ((D3D.EffectScalarVariable) _param).Set(values);
                if(r.Code < 0) {
                    throw D3D10Helper.GetExceptionFromResult(r);
                }
            } else {
                throw new ArgumentOutOfRangeException("Bool array is too large to be set to effect parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Single value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a float.</exception>
        public void SetValue(float value) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Single
                || IsArray()) {
                throw new InvalidCastException("Parameter is not a float.");
            }

            SlimDX.Result r = ((D3D.EffectScalarVariable) _param).Set(value);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of singles</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a float[].</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(float[] values) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Single
                || !IsArray()) {
                throw new InvalidCastException("Parameter is not a float[].");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                SlimDX.Result r = ((D3D.EffectScalarVariable) _param).Set(values);
                if(r.Code < 0) {
                    throw D3D10Helper.GetExceptionFromResult(r);
                }
            } else {
                throw new ArgumentOutOfRangeException("Float array is too large to be set to effect parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Int value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a int.</exception>
        public void SetValue(int value) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Int32
                || IsArray()) {
                    throw new InvalidCastException("Parameter is not an int.");
            }

            SlimDX.Result r = ((D3D.EffectScalarVariable) _param).Set(value);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of ints</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not an int[].</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(int[] values) {
            if(_paramClass != EffectParameterClass.Scalar || _paramType != EffectParameterType.Int32
                || !IsArray()) {
                    throw new InvalidCastException("Parameter is not an int[].");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                SlimDX.Result r = ((D3D.EffectScalarVariable) _param).Set(values);
                if(r.Code < 0) {
                    throw D3D10Helper.GetExceptionFromResult(r);
                }
            } else {
                throw new ArgumentOutOfRangeException("Int array is too large to be set to effect parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Matrix value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a matrix.</exception>
        public void SetValue(Matrix value) {
            if(_paramClass != EffectParameterClass.Matrix || IsArray()) {
                throw new InvalidCastException("Parameter is not a matrix.");
            }

            SDX.Matrix m;

            m.M11 = value.M11;
            m.M12 = value.M12;
            m.M13 = value.M13;
            m.M14 = value.M14;

            m.M21 = value.M21;
            m.M22 = value.M22;
            m.M23 = value.M23;
            m.M24 = value.M24;

            m.M31 = value.M31;
            m.M32 = value.M32;
            m.M33 = value.M33;
            m.M34 = value.M34;

            m.M41 = value.M41;
            m.M42 = value.M42;
            m.M43 = value.M43;
            m.M44 = value.M44;

            SlimDX.Result r = ((D3D.EffectMatrixVariable) _param).SetMatrix(m);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of matrices</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Matrix[].</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(Matrix[] values) {
            if(_paramClass != EffectParameterClass.Matrix || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Matrix[].");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                if(_isColumnMatrix) {
                    _elementArray.Position = 0;
                    Matrix transpose;
                    //Need to transpose each matrix in the array
                    for(int i = 0; i < values.Length; i++) {
                        Matrix.Transpose(ref values[i], out transpose);
                        _elementArray.Write<Matrix>(transpose);
                    }
                } else {
                    //Already in the right order
                    _elementArray.WriteRange<Matrix>(values, 0, values.Length);
                }
                _elementArray.Position = 0;
                _param.SetRawValue(_elementArray, Matrix.SizeInBytes * values.Length);
            } else {
                throw new ArgumentOutOfRangeException("Matrix array is too large to be set to effect parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Matrix transpose value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Matrix.</exception>
        public void SetValueTranspose(Matrix value) {
            if(_paramClass != EffectParameterClass.Matrix || IsArray()) {
                throw new InvalidCastException("Parameter is not a matrix.");
            }

            SDX.Matrix m;
            m.M11 = value.M11;
            m.M12 = value.M21;
            m.M13 = value.M31;
            m.M14 = value.M41;
            m.M21 = value.M12;
            m.M22 = value.M22;
            m.M23 = value.M32;
            m.M24 = value.M42;
            m.M31 = value.M13;
            m.M32 = value.M23;
            m.M33 = value.M33;
            m.M34 = value.M43;
            m.M41 = value.M14;
            m.M42 = value.M24;
            m.M43 = value.M34;
            m.M44 = value.M44;

            SlimDX.Result r = ((D3D.EffectMatrixVariable) _param).SetMatrix(m);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of transposed matrices</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Matrix[].</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValueTranspose(Matrix[] values) {
            if(_paramClass != EffectParameterClass.Matrix || !IsArray()) {
                throw new InvalidCastException("Parameter is not a Matrix[].");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                if(_isColumnMatrix) {
                    //Column major, so writing row major will automatically leave it transposed
                    _elementArray.WriteRange<Matrix>(values, 0, values.Length);
                } else {
                    //Otherwise row major, and must transpose
                    _elementArray.Position = 0;
                    Matrix transpose;
                    for(int i = 0; i < values.Length; i++) {
                        Matrix.Transpose(ref values[i], out transpose);
                        _elementArray.Write<Matrix>(transpose);
                    }
                }
                _elementArray.Position = 0;
                _param.SetRawValue(_elementArray, Matrix.SizeInBytes * values.Length);
            } else {
                throw new ArgumentOutOfRangeException("Matrix array is too large to be set to effect parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Vector2 value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Vector2.</exception>
        public void SetValue(Vector2 value) {
            if(_paramClass != EffectParameterClass.Vector || IsArray() || !IsVector(2)) {
                throw new InvalidCastException("Parameter is not a Vector2.");
            }
            SDX.Vector2 v;
            v.X = value.X;
            v.Y = value.Y;
            SlimDX.Result r = ((D3D.EffectVectorVariable) _param).Set(v);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of Vector2</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Vector2[].</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(Vector2[] values) {
            if(_paramClass != EffectParameterClass.Vector || !IsArray() || !IsVector(2)) {
                throw new InvalidCastException("Parameter is not a Vector2[].");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                _elementArray.WriteRange<Vector2>(values, 0, values.Length);
                _elementArray.Position = 0;
                _param.SetRawValue(_elementArray, Vector2.SizeInBytes * values.Length);
            } else {
                throw new ArgumentOutOfRangeException("Vector2 array is too large to be set to shader parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Vector3 value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Vector3.</exception>
        public void SetValue(Vector3 value) {
            if(_paramClass != EffectParameterClass.Vector || IsArray() || !IsVector(3)) {
                throw new InvalidCastException("Parameter is not a Vector3");
            }
            SDX.Vector3 v;
            v.X = value.X;
            v.Y = value.Y;
            v.Z = value.Z;
            SlimDX.Result r = ((D3D.EffectVectorVariable) _param).Set(v);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of Vector3</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Vector3[].</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(Vector3[] values) {
            if(_paramClass != EffectParameterClass.Vector || !IsArray() || !IsVector(3)) {
                throw new InvalidCastException("Parameter is not a Vector3[]");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                _elementArray.WriteRange<Vector3>(values, 0, values.Length);
                _elementArray.Position = 0;
                _param.SetRawValue(_elementArray, Vector3.SizeInBytes * values.Length);
            } else {
                throw new ArgumentOutOfRangeException("Vector3 array is too large to be set to shader parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Vector4 value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Vector4.</exception>
        public void SetValue(Vector4 value) {
            if(_paramClass != EffectParameterClass.Vector || IsArray() || !IsVector(4)) {
                throw new InvalidCastException("Parameter is not a Vector4");
            }
            SDX.Vector4 v;
            v.X = value.X;
            v.Y = value.Y;
            v.Z = value.Z;
            v.W = value.W;
            SlimDX.Result r = ((D3D.EffectVectorVariable) _param).Set(v);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of Vector4</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a Vector4[].</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(Vector4[] values) {
            if(_paramClass != EffectParameterClass.Vector || !IsArray() || !IsVector(4)) {
                throw new InvalidCastException("Parameter is not a Vector4[]");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                _elementArray.WriteRange<Vector4>(values, 0, values.Length);
                _elementArray.Position = 0;
                _param.SetRawValue(_elementArray, Vector4.SizeInBytes * values.Length);
            } else {
                throw new ArgumentOutOfRangeException("Vector4 array is too large to be set to shader parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Quaternion value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a 4 component vector.</exception>
        public void SetValue(Quaternion value) {
            if(_paramClass != EffectParameterClass.Vector || IsArray() || _columnCount != 4) {
                throw new InvalidCastException("Parameter is not a 4 component vector.");
            }
            SDX.Vector4 v;
            v.X = value.X;
            v.Y = value.Y;
            v.Z = value.Z;
            v.W = value.W;
            SlimDX.Result r = ((D3D.EffectVectorVariable) _param).Set(v);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of quaternions</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a 4 component vector array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(Quaternion[] values) {
            if(_paramClass != EffectParameterClass.Vector || !IsArray() || _columnCount != 4) {
                throw new InvalidCastException("Parameter is not a 4 component vector array.");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                _elementArray.WriteRange<Quaternion>(values, 0, values.Length);
                _elementArray.Position = 0;
                _param.SetRawValue(_elementArray, Quaternion.SizeInBytes * values.Length);
            } else {
                throw new ArgumentOutOfRangeException("Quaternion array is too large to be set to shader parameter.");
            }
        }
        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Color value (interpreted as a 4-float vector)</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a 4 component vector.</exception>
        public void SetValue(Color value) {
            if(_paramClass != EffectParameterClass.Vector || IsArray() || !IsVector(4)) {
                throw new InvalidCastException("Parameter is not a 4 component vector.");
            }
            SDX.Vector4 v;
            Vector4 cv = value.ToVector4();

            v.X = cv.X;
            v.Y = cv.Y;
            v.Z = cv.Z;
            v.W = cv.W;
            SlimDX.Result r = ((D3D.EffectVectorVariable) _param).Set(v);
            if(r.Code < 0) {
                throw D3D10Helper.GetExceptionFromResult(r);
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="value">Array of colors (interpreted as a 4-float vector)</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a 4 component vector array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        public void SetValue(Color[] values) {
            if(_paramClass != EffectParameterClass.Vector || !IsArray() || !IsVector(4)) {
                throw new InvalidCastException("Parameter is not a 4 component vector array.");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                _elementArray.Position = 0;
                //Transform each color to RGBA vector
                for(int i = 0; i < values.Length; i++) {
                    _elementArray.Write<Vector4>(values[i].ToVector4());
                }
                _elementArray.Position = 0;
                _param.SetRawValue(_elementArray, Vector4.SizeInBytes * values.Length);
            } else {
                throw new ArgumentOutOfRangeException("Color array is too large to be set to shader parameter.");
            }
        }

        /// <summary>
        /// Sets the value of the parameter.
        /// </summary>
        /// <param name="value">Texture value</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a texture of the correct type.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the value to set is null.</exception>
        /// <exception cref="System.InvalidCastException">Thrown if the value is not of proper parameter type that is expected.</exception>
        public void SetValue(Texture value) {
            if(_paramClass != EffectParameterClass.Object || IsArray()) {
                throw new InvalidCastException("Parameter is not a texture.");
            }

            if(value == null) {
                throw new ArgumentNullException("Texture cannot be null");
            }

            switch(_paramType) {
                case EffectParameterType.Texture1D:
                    Texture1D tex1D = value as Texture1D;
                    if(tex1D == null) {
                        throw new InvalidCastException("Expecting Texture1D");
                    }
                    SlimDX.Result r = ((D3D.EffectResourceVariable) _param).SetResource(((D3D10Texture1DImplementation)tex1D.Implementation).D3D10ShaderResourceView);
                    if(r.Code < 0) {
                        throw D3D10Helper.GetExceptionFromResult(r);
                    }
                    _cachedTexture = new WeakReference(value);
                    break;
                case EffectParameterType.Texture2D:
                    Texture2D tex2D = value as Texture2D;
                    if(tex2D == null) {
                        throw new InvalidCastException("Expecting Texture2D");
                    }
                    r = ((D3D.EffectResourceVariable) _param).SetResource(((D3D10Texture2DImplementation)tex2D.Implementation).D3D10ShaderResourceView);
                    if(r.Code < 0) {
                        throw D3D10Helper.GetExceptionFromResult(r);
                    }
                    _cachedTexture = new WeakReference(value);
                    break;
                case EffectParameterType.Texture3D:
                    Texture3D tex3D = value as Texture3D;
                    if(tex3D == null) {
                        throw new InvalidCastException("Expecting Texture3D");
                    }
                    r = ((D3D.EffectResourceVariable) _param).SetResource(((D3D10Texture3DImplementation)tex3D.Implementation).D3D10ShaderResourceView);
                    if(r.Code < 0) {
                        throw D3D10Helper.GetExceptionFromResult(r);
                    }
                    _cachedTexture = new WeakReference(value);
                    break;
                case EffectParameterType.TextureCube:
                    TextureCube texCube = value as TextureCube;
                    if(texCube == null) {
                        throw new InvalidCastException("Expecting TextureCube");
                    }
                    r = ((D3D.EffectResourceVariable) _param).SetResource(((D3D10TextureCubeImplementation) texCube.Implementation).D3D10ShaderResourceView);
                    if(r.Code < 0) {
                        throw D3D10Helper.GetExceptionFromResult(r);
                    }
                    _cachedTexture = new WeakReference(value);
                    break;
            }
        }

        /// <summary>
        /// Sets the value of the parameter's elements.
        /// </summary>
        /// <param name="values">Array of textures</param>
        /// <exception cref="System.InvalidCastException">Thrown if the parameter is not a texture array.</exception>
        /// <exception cref="System.ArgumentOutOfRangeException">Thrown if the array is too large to be set</exception>
        /// <exception cref="System.ArgumentNullException">Thrown if the array is null or of empty length.</exception>
        /// <exception cref="System.InvalidCastException">Thrown if the values in the array are not all the same expected parameter type.</exception>
        /// <exception cref="System.ArgumentException">Thrown if the textures are not homogeneous.</exception>
        public void SetValue(Texture[] values) {
            if(_paramClass != EffectParameterClass.Object || !IsArray()) {
                throw new InvalidCastException("Parameter is not a texture array.");
            }

            if(values == null || values.Length == 0) {
                throw new ArgumentNullException("Array cannot be null");
            }

            if(values.Length <= _elements.Count) {
                int width = 0;
                int height = 0;
                int mipCount = 0;
                SurfaceFormat format = SurfaceFormat.Color;
                SDX.Result r;

                Texture first = values[0];

                if (first != null) {
                    switch (_paramType) {
                        case EffectParameterType.Texture1D:
                            for (int i = 0; i < values.Length; i++) {
                                Texture1D tex1D = values[i] as Texture1D;
                                if (tex1D == null) {
                                    throw new InvalidCastException("Expecting Texture1D");
                                }
                                if (i == 0) {
                                    width = tex1D.Width;
                                    mipCount = tex1D.MipCount;
                                    format = tex1D.Format;
                                } else {
                                    if (tex1D.Width != width || tex1D.MipCount != mipCount || tex1D.Format != format) {
                                        throw new ArgumentException(String.Format("Texture1D {0} in array at index {0} does not match previous textures in width, mip count, or format.", i));
                                    }
                                }
                                _cachedTextureArray[i] = new WeakReference(tex1D);
                                _srvArray[i] = ((D3D10Texture1DImplementation)tex1D.Implementation).D3D10ShaderResourceView;
                            }
                            r = ((D3D.EffectResourceVariable)_param).SetResourceArray(_srvArray);
                            if (r.Code < 0) {
                                throw D3D10Helper.GetExceptionFromResult(r);
                            }
                            break;
                        case EffectParameterType.Texture2D:
                            for (int i = 0; i < values.Length; i++) {
                                Texture2D tex2D = values[i] as Texture2D;
                                if (tex2D == null) {
                                    throw new InvalidCastException("Expecting Texture2D");
                                }
                                if (i == 0) {
                                    width = tex2D.Width;
                                    height = tex2D.Height;
                                    mipCount = tex2D.MipCount;
                                    format = tex2D.Format;
                                } else {
                                    if (tex2D.Width != width || tex2D.Height != height || tex2D.MipCount != mipCount || tex2D.Format != format) {
                                        throw new ArgumentException(String.Format("Texture2D in array at index {0} does not match previous textures in width, height, mip count, or format.", i));
                                    }
                                }
                                _cachedTextureArray[i] = new WeakReference(tex2D);
                                _srvArray[i] = ((D3D10Texture2DImplementation)tex2D.Implementation).D3D10ShaderResourceView;
                            }
                            r = ((D3D.EffectResourceVariable)_param).SetResourceArray(_srvArray);
                            if (r.Code < 0) {
                                throw D3D10Helper.GetExceptionFromResult(r);
                            }
                            break;
                        case EffectParameterType.Texture3D:
                            throw new InvalidCastException("Only 1D, 2D, and Cube textures are supported.");
                        case EffectParameterType.TextureCube:
                            for (int i = 0; i < values.Length; i++) {
                                TextureCube texCube = values[i] as TextureCube;
                                if (texCube == null) {
                                    throw new InvalidCastException("Expecting TextureCube");
                                }
                                if (i == 0) {
                                    width = texCube.Size;
                                    mipCount = texCube.MipCount;
                                    format = texCube.Format;
                                } else {
                                    if (texCube.Size != width || texCube.MipCount != mipCount || texCube.Format != format) {
                                        throw new ArgumentException(String.Format("TextureCube in array at index {0} does not match previous textures in size, mip count, or format.", i));
                                    }
                                }
                                _cachedTextureArray[i] = new WeakReference(texCube);
                                _srvArray[i] = ((D3D10TextureCubeImplementation)texCube.Implementation).D3D10ShaderResourceView;
                            }
                            r = ((D3D.EffectResourceVariable)_param).SetResourceArray(_srvArray);
                            if (r.Code < 0) {
                                throw D3D10Helper.GetExceptionFromResult(r);
                            }
                            break;
                    }
                    Array.Clear(_srvArray, 0, _srvArray.Length);
                } else {
                    Array.Clear(_srvArray, 0, _srvArray.Length);
                    r = ((D3D.EffectResourceVariable)_param).SetResourceArray(_srvArray);
                    if (r.Code < 0) {
                        throw D3D10Helper.GetExceptionFromResult(r);
                    }
                }
            } else {
                throw new ArgumentOutOfRangeException("Texture array is too large to be set to shader parameter.");
            }
        }
    }
}
